/*
 * easysmtp - A simple C lib in Linux to help you send mails in an easy way 
 * Copyright (C) 2012-2013, easysmtp developers and contributors
 *
 * easysmtp is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * easysmtp is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with easysmtp; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "easysmtp.h"
#include "attach.h"
#include "process_chain.h"
#include "ssl.h"
#include <time.h>

static int deal_content(char **text, int *text_len, const char *content);
static void destroy_list(char **list, int list_len);

//SMTP结构的初始化
SMTP*
smtp_init(void) 
{
	SMTP *stemp = (SMTP *)malloc(sizeof(SMTP));
	if(stemp == NULL) {
		return NULL;
	}

	stemp->connect_tv = 
		(struct timeval *)malloc(sizeof(struct timeval));
	stemp->recv_tv = 
		(struct timeval *)malloc(sizeof(struct timeval));
	return stemp;
}

//设置smtp服务器地址
int 
set_server_addr(SMTP *smtpr, const char *server_addr) 
{
	if(strlen(server_addr) >= sizeof(smtpr->server_addr) ) {
		serrno = SETERROR; 
		return SYS_ERROR ;	
	}
	strcpy(smtpr->server_addr, server_addr);	
	return SMTP_SUCCESS;
}

//设置域名（服务器地址，域名选择其一）
int
set_domain(SMTP *smtpr, const char *domain) 
{
	if(strlen(domain) >= sizeof(smtpr->domain)) {
		serrno = SETERROR;
		return SYS_ERROR;
	}	
	strcpy(smtpr->domain, domain);
	smtpr->domain_flag = 1;
	return SMTP_SUCCESS;
}

//选择认证方式（默认为AUTH LOGIN）
int
set_auth_method(SMTP *smtpr, const char *auth_method) 
{
	if(!strcmp(auth_method, "plain")) {
		smtpr->method_flag = 1;			
	}
	return SMTP_SUCCESS;
}

//设置邮箱
int 
set_username(SMTP *smtpr, const char *username) 
{
	if(strlen(username) >= sizeof(smtpr->username)) {
		serrno = SETERROR;
		return SYS_ERROR;
	}
	strcpy(smtpr->username, username);
	return SMTP_SUCCESS;
}

//设置邮箱密码
int 
set_passwd(SMTP *smtpr, const char *passwd) 
{
	if(strlen(passwd) >= sizeof(smtpr->passwd)) {
		serrno = SETERROR;
		return SYS_ERROR;
	}
	strcpy(smtpr->passwd, passwd);
	return SMTP_SUCCESS;
}

//设置收件人列表
int
set_recv_list(SMTP *smtpr, char recv_list[][SMTP_MAXLEN+1], int len)
{
	int i;

	//如果原来没有收件人，则开辟一块内存。
	if(smtpr->recv_len == 0) {
		smtpr->recv_list = (char **)malloc(len * sizeof(char *));
	}
	//如果之前已经存储了收件人，则扩充内存
	else {
		smtpr->recv_list = (char **)realloc(smtpr->recv_list,
					smtpr->recv_len+len);
	}

	//为每个存储收件人的指针分配内存
	for(i = smtpr->recv_len; i < smtpr->recv_len+len; i++) {
		if((smtpr->recv_list[i] = 
		(char *)malloc(strlen(recv_list[i-smtpr->recv_len])+1))
						== NULL) {
			//分配内存为空，错误设置为SETERROR
			serrno = SETERROR;
			return SMTP_ERROR;
		}
		strcpy(smtpr->recv_list[i], recv_list[i-smtpr->recv_len]);
	}
	smtpr->recv_len += len;
	return SMTP_SUCCESS;
}

//增加一位收件人
int 
add_one_recv(SMTP *smtpr, const char *recv) 
{
	if(smtpr->recv_len == 0) {
		smtpr->recv_list = (char **)malloc(sizeof(char *));
	}
	else {
		smtpr->recv_list = (char **)realloc(smtpr->recv_list,
					smtpr->recv_len+1);
	}
	//为新增的收件人分配内存
	if((smtpr->recv_list[smtpr->recv_len] = (char *)malloc
					(strlen(recv)+1)) == NULL){
		serrno = SETERROR;
		return SMTP_ERROR;
	}
	strcpy(smtpr->recv_list[smtpr->recv_len++], recv);
	return SMTP_SUCCESS;
}

//设置抄送列表
int
set_cc_list(SMTP *smtpr, char cc_list[][SMTP_MAXLEN+1], int len) 
{	
	int i;

	if(smtpr->cc_len == 0) {
		smtpr->cc_list = (char **)malloc(len * sizeof(char *));	
	}
	else {
		smtpr->cc_list = (char **)realloc(smtpr->cc_list, 
						smtpr->cc_len+len);
	}

	for(i = smtpr->cc_len; i < smtpr->cc_len+len; i++) {
		if((smtpr->cc_list[i] = 
		(char *)malloc(strlen(cc_list[i-smtpr->cc_len])+1))
							== NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
		strcpy(smtpr->cc_list[i], cc_list[i-smtpr->cc_len]);
	}
	smtpr->cc_len += len;
	return SMTP_SUCCESS;
}

//增加一位抄送
int
add_one_cc(SMTP *smtpr, const char *cc) 
{
	if(smtpr->cc_len == 0) {
		smtpr->cc_list = (char **)malloc(sizeof(char *));
	}
	else {
		smtpr->cc_list = (char **)realloc(smtpr->cc_list,
					smtpr->cc_len+1);
	}
	if((smtpr->cc_list[smtpr->cc_len] = (char *)malloc
					(strlen(cc)+1)) == NULL){
		serrno = SETERROR;
		return SMTP_ERROR;
	}
	strcpy(smtpr->cc_list[smtpr->cc_len++], cc);
	return SMTP_SUCCESS;
}

//设置密送列表
int
set_bcc_list(SMTP *smtpr, char bcc_list[][SMTP_MAXLEN+1], int len) 
{	
	int i;

	if(smtpr->bcc_len == 0) {
		smtpr->bcc_list = (char **)malloc(len * sizeof(char *));
	}
	else {
		smtpr->bcc_list = (char **)realloc(smtpr->bcc_list, 
						len+smtpr->bcc_len);	
	}

	for(i = smtpr->bcc_len; i < smtpr->bcc_len+len; i++) {
		if((smtpr->bcc_list[i] = 
		(char *)malloc(strlen(bcc_list[i-smtpr->bcc_len])+1)) 
							== NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
		strcpy(smtpr->bcc_list[i], bcc_list[i-smtpr->bcc_len]);
	}
	smtpr->bcc_len += len;
	return SMTP_SUCCESS;
}

//增加一位密送
int 
add_one_bcc(SMTP *smtpr, const char *bcc) 
{
	if(smtpr->bcc_len == 0) {
		smtpr->bcc_list = (char **)malloc(sizeof(char *));
	}
	else {
		smtpr->bcc_list = (char **)realloc(smtpr->bcc_list,
					smtpr->bcc_len+1);
	}
	if((smtpr->bcc_list[smtpr->bcc_len] = (char *)malloc
					(strlen(bcc)+1)) == NULL){
		serrno = SETERROR;
		return SMTP_ERROR;
	}
	strcpy(smtpr->bcc_list[smtpr->bcc_len++], bcc);
	return SMTP_SUCCESS;
}

//设置connect非阻塞超时时间（默认采用阻塞连接）
int 
set_connect_time_out(SMTP *smtpr, int sec) 
{
	smtpr->connect_tv->tv_sec = sec;
	return SMTP_SUCCESS;
}

//设置从服务器接受消息的等待时间（默认为一直等待）
int
set_recv_time_out(SMTP *smtpr, int sec) 
{
	smtpr->recv_tv->tv_sec = sec;
	return SMTP_SUCCESS;
}

//初始化一个MAIL结构
MAIL*
mail_init(void) 
{
	MAIL *mtemp = (MAIL*)malloc(sizeof(MAIL));
	if(mtemp == NULL) {
		return NULL;
	}

	mtemp->text_plain_len = 0;
	mtemp->text_html_len = 0;
	return mtemp;
}

//设置邮件主题
int 
set_title(MAIL *mpr, const char *title) 
{
	if(strlen(title) >= sizeof(mpr->title)) {
		serrno = SETERROR;
		return SMTP_ERROR;
	}
	strcpy(mpr->title, title);
	return SMTP_SUCCESS;
}

//设置邮件内容（可以选择plain（文本）类型和html类型）
int
set_content(MAIL *mpr, const char *content, const char *content_type) 
{
	strcpy(mpr->content_type, content_type);

	//根据不同类型，给deal_content函数不同参数
	if(!strcmp(content_type, "plain")) {
		return deal_content(&mpr->text_plain, &mpr->text_plain_len,
						content);	
	}
	else if(!strcmp(content_type, "html")) {
		return deal_content(&mpr->text_html, &mpr->text_html_len,
						content);
	}
	//用户类型参数的输入有误，错误SETERROR
	serrno = SETERROR;
	return SMTP_ERROR;
}

//处理邮件内容函数
int 
deal_content(char **text, int *text_len, const char *content) 
{
	//根据之前是否添加过内容决定是开辟还是扩充
	if(!*text_len) {
		if((*text = (char *)malloc(strlen(content)+1)) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}
	else {
		if((*text = (char *)realloc(
				*text,strlen(content)
					+*text_len)) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}

	//拼接邮件内容
	strcat(&(*text)[*text_len], content);
	*text_len += strlen(content);
	return SMTP_SUCCESS;
}

//设置附件列表
int
set_attachment_list(MAIL *mpr,  char file_path_list[][SMTP_MAXLEN+1],
		char file_name_list[][SMTP_MAXLEN+1], int len) 
{
	int i;

	if(!mpr->att_len) {
		if((mpr->file_path_list = 
			(char **)malloc(len * sizeof(char *))) == NULL ||
			(mpr->file_name_list = 
	 		(char **)malloc(len * sizeof(char *))) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}
	else {
		if((mpr->file_path_list = 
			(char **)realloc(mpr->file_path_list, 
					len+mpr->att_len)) == NULL ||
			(mpr->file_name_list =
			(char **)realloc(mpr->file_name_list,
					len+mpr->att_len)) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}

	for(i = mpr->att_len; i < len+mpr->att_len; i++) {
		if((mpr->file_path_list[i] = 
		(char *)malloc(strlen(file_path_list[i])+1)) == NULL ||
			(mpr->file_name_list[i] = (char *)malloc(
				strlen(file_name_list[i])+1)) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
		strcpy(mpr->file_path_list[i], 
				file_path_list[i-mpr->att_len]);
		strcpy(mpr->file_name_list[i],
				file_name_list[i-mpr->att_len]);
	}
	mpr->att_len += len;
	return SMTP_SUCCESS;
}

//添加一个附件
int
add_one_attachment(MAIL *mpr, const char *file_path, 
		const char *file_name)
{
	if(!mpr->att_len) {
		if((mpr->file_path_list = 
			(char **)malloc(sizeof(char *))) == NULL ||
			(mpr->file_name_list = 
		 	(char **)malloc(sizeof(char *))) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}
	else {
		if((mpr->file_path_list = 
			(char **)realloc(mpr->file_path_list, 
					mpr->att_len+1)) == NULL ||
			(mpr->file_name_list =
			(char **)realloc(mpr->file_name_list,
					mpr->att_len+1)) == NULL) {
			serrno = SETERROR;
			return SMTP_ERROR;
		}
	}
	if((mpr->file_path_list[mpr->att_len] = (char *)malloc
				(strlen(file_path)+1)) == NULL ||
		(mpr->file_name_list[mpr->att_len] = 
		 	(char *)malloc(strlen(file_name)+1)) == NULL){
		serrno = SETERROR;
		return SMTP_ERROR;
	}
	strcpy(mpr->file_path_list[mpr->att_len], file_path);
	strcpy(mpr->file_name_list[mpr->att_len], file_name);
	mpr->att_len++;
	return SMTP_SUCCESS;
}

//向SMTP服务器发送消息
int
send_msg(SMTP *smtpr, char *buf) 
{
	//如果ssl的标记位为1，使用ssl的发送函数
	if(1 == smtpr->ssl_flag) {
		if(SSL_write(smtpr->ssl, buf, strlen(buf)) <= 0) {
			return SSL_ERROR;
		}
	}
	//否则选择普通的发送函数
	else {
		if(send(smtpr->sockfd, buf, strlen(buf), 0) == -1) {
			return SYS_ERROR;
		}
	}
	return SMTP_SUCCESS;
}

//处理smtp服务器返回内容
int
deal_return(SMTP *smtpr) 
{
	int i;
	char return_num[10] = {0};
	//SMTP返回的错误状态码
	char error[][10] = {"421", "450", "451", "452", "500", "501",
				"502", "503", "504", "550", "551", "552",
				"553", "554", "535"};
	//自定义的SMTP错误代码
	int error_num[16] = {SETERROR, SSUNAVAILABLE, SMBOXUNAVAILABLE,
				SLOCALERROR, SNOSTORAGE, SCMDERROR,
				SPARAERROR, SCNOIMPLEMENT, SBADCOMMANDS,
				SPNOIMPLEMENT, SNOTAKEN, SUSERNOTLOCAL,
				SEXCEEDED, SMBOXNOTALLOWED, STRANSFAILED,
				SAUTHFAILED};

	strncpy(return_num, smtpr->buf, 3);	
	//状态码以'2'和'3'开头的都表示成功
	if(return_num[0] == '2' || return_num[0] == '3') {
		return SMTP_SUCCESS;
	}
	//判断返回码对应什么错误
	for(i = 0; i < sizeof(error)/sizeof(error[0]); i++) {
		if(strcmp(return_num, error[i]) == 0) {
			serrno = error_num[i+1];
			return SMTP_ERROR;
		}
	}
	serrno = SMTPERROR;
	return SMTP_ERROR;
}

//读取服务器发来的消息
int 
read_msg(SMTP *smtpr) 
{
	memset(smtpr->buf, 0, sizeof(smtpr->buf));
	if(1 == smtpr->ssl_flag) {
		if(SSL_read(smtpr->ssl, smtpr->buf, 
					sizeof(smtpr->buf)) <= 0) {
			return SSL_ERROR;
		}
	}
	else {
		if(recv(smtpr->sockfd,smtpr->buf, 
					sizeof(smtpr->buf), 0) == -1) {
			return SYS_ERROR;
		}
	}
	//处理smtp服务器返回内容
	//return deal_return(smtpr);
	printf("%s\n", smtpr->buf);
	return SMTP_SUCCESS;
}
//发送邮件函数
//
int
send_mail(SMTP *smtpr, MAIL *mpr) 
{
	smtpr->ssl_flag = 0;
	struct sockaddr_in *server = (struct sockaddr_in *)
				malloc(sizeof(struct sockaddr_in *));
	pre_connect(smtpr, server, SMTPPORT);
	struct sockaddr_in sv = *server;

	if(smtp_connect((struct sockaddr *)&sv, 
				sizeof(sv), smtpr->connect_tv->tv_sec, 
				smtpr) == SYS_ERROR) {
		return SYS_ERROR;
	}
	//设置读写时间
	if(-1 == setsockopt(smtpr->sockfd, SOL_SOCKET, SO_RCVTIMEO,
			smtpr->recv_tv, sizeof(struct timeval))) {
		return SYS_ERROR;
	}
	return exec_process(smtpr, mpr);
}

void 
destroy_list(char **list, int list_len) 
{
	int i;

	for(i= 0; i< list_len ; i++){
		free (list[i]);
	}
	free(list);
}

void
smtp_destroy(SMTP*smtpr , MAIL*mpr) 
{
	free(smtpr->connect_tv);
	free(smtpr->recv_tv);
	if(smtpr->recv_len) {
		destroy_list(smtpr->recv_list, smtpr->recv_len);
	}
	if (smtpr->cc_len) {
		destroy_list(smtpr->cc_list, smtpr->cc_len);
	}
	if(smtpr->bcc_len) {
		destroy_list(smtpr->bcc_list, smtpr->bcc_len);
	}
	if(mpr->text_plain_len) {
		free(mpr->text_plain);
	}
	if(mpr->text_html_len) {
		free(mpr->text_html);
	}
	if(mpr->att_len) {
		destroy_list(mpr->file_path_list, mpr->att_len);
		destroy_list(mpr->file_name_list, mpr->att_len);
	}
	free(smtpr);
	free(mpr);
}
